//
//  UIImage+Extension.swift
//  Library_y
//
//  Created by JC on 2023/6/6.
//

import UIKit
import Foundation
import AVFoundation
import ImageIO

// imageType枚挙
public enum imageType {
    case JPG,PNG,Tiff,gif,webp,bmp,None
}

public extension UIImage {
    
    func applyFilter(with name: String, parameters: [String : Any]? = nil) -> UIImage? {
        
        let filter = CIFilter(name: name, parameters: parameters)
        filter?.setValue(CIImage(image: self), forKey: kCIInputImageKey)
        if let output = filter?.outputImage {
            let context = CIContext()
            if let cgImage = context.createCGImage(output, from: output.extent) {
                return UIImage(cgImage: cgImage)
            }
        }
        return nil
    }
    
    // 通过文件头来判断图片类型
    internal func contentTypeForImageData(data: NSData) -> imageType {
        var c:UInt8?
        data.getBytes(&c, length: 1)
        switch c {
        case 0xFF:
            return imageType.JPG;
        case 0x89:
            return imageType.PNG
        case 0x47:
            return imageType.gif
        case 0x49,0x4D:
            return imageType.Tiff
        case 0x42:
            return imageType.bmp
        case 0x52:
            if (data.length < 12) {
                return imageType.None;
            }
            let testString:NSString = NSString(data: data.subdata(with: NSMakeRange(0, 12)), encoding: String.Encoding.ascii.rawValue)!
            if testString.hasPrefix("RIFF"),testString.hasSuffix("WEBP") {
                return imageType.webp
            }
        default:return imageType.None
        }
        return imageType.None
    }
}

// 通过输入rgb值返回一个该颜色的img
extension UIImage{
    
    public class func initWithImage(color:UIColor)->UIImage{
        let rect = CGRect(x: 0,y: 0,width: 1,height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    
    public class func renderImageWithColor(_ color: UIColor, size: CGSize) -> UIImage {
        UIGraphicsBeginImageContext(size)
        guard let context = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return UIImage()
        }
        context.setFillColor(color.cgColor);
        context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height));
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img ?? UIImage()
    }
}

public extension UIImage {
    
    //返 回裁剪区域图片,返回裁剪区域大小图片
    func clip(withImageRect clipRect: CGRect, clipImage: UIImage?) -> UIImage? {
        UIGraphicsBeginImageContext(clipRect.size)
        clipImage?.draw(in: clipRect)
        let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    
    // 将图片裁剪成指定比例（多余部分自动删除）
    func crop(ratio: CGFloat) -> UIImage {
        //计算最终尺寸
        var newSize = CGSize.zero
        if size.width/size.height > ratio {
            newSize = CGSize(width: size.height * ratio, height: size.height)
        }else{
            newSize = CGSize(width: size.width, height: size.width / ratio)
        }
        
        ////图片绘制区域
        var rect = CGRect.zero
        rect.size.width  = size.width
        rect.size.height = size.height
        rect.origin.x    = (newSize.width - size.width ) / 2.0
        rect.origin.y    = (newSize.height - size.height ) / 2.0
        
        //绘制并获取最终图片
        UIGraphicsBeginImageContext(newSize)
        draw(in: rect)
        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return scaledImage!
    }
    
    func cropped(to size: CGSize) -> UIImage? {
        guard let cgImage = cgImage?.cropping(to: .init(origin: .init(x: (self.size.width - size.width) / 2,
                                                  y: (self.size.height - size.height) / 2),
                                    size: size)) else { return nil }
        return UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
    }
}


public extension UIImage {
    
    /// 根据颜色创建 UIImage
    convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
        
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        color.setFill()
        UIRectFill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        guard let cgImage = image?.cgImage else { return nil }
        self.init(cgImage: cgImage)
    }
    
    /// 添加 UIImage 合成新的 UIImage
    ///
    /// - parameter foreGroundImage: 要添加的 UIImage
    /// - parameter point:           添加的图的起始点
    ///
    /// - returns: 合成的 UIImage
    func addImage(image foreGroundImage: UIImage, atPoint point: CGPoint = CGPoint(x: 0, y: 0)) -> UIImage? {
        return UIImage.drawImage(image: foreGroundImage, inImage: self, atPoint: point)
    }
    
    /// 将前景与背景 UIImage 合成一个 UIImage
    ///
    /// - parameter foreGroundImage: 前景 UIImage
    /// - parameter backgroundImage: 背景 UIImage
    /// - parameter point:           前景位于背景的起始点
    ///
    /// - returns: 合成的 UIImage
    class func drawImage(image foreGroundImage: UIImage, inImage backgroundImage: UIImage, atPoint point: CGPoint = CGPoint(x: 0, y: 0)) -> UIImage? {
        
        UIGraphicsBeginImageContextWithOptions(backgroundImage.size, false, 0.0)
        
        backgroundImage.draw(in: CGRect(x: 0, y: 0, width: backgroundImage.size.width, height: backgroundImage.size.height))
        foreGroundImage .draw(in: CGRect(x: point.x, y: point.y, width: foreGroundImage.size.width, height: foreGroundImage.size.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        return newImage
    }
    
    /// 根据给定的颜色获取重绘后的图片
    ///
    /// - parameter color: 颜色
    ///
    /// - returns: 重绘后的图片
    func tint(with color: UIColor) -> UIImage? {
        var image: UIImage? = withRenderingMode(.alwaysTemplate)
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        color.set()
        image?.draw(in: CGRect(origin: .zero, size: size))
        image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
    
    func creatImageWithColor(color: UIColor, size: CGSize) -> UIImage? {
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
    
    /// 剪切图片
    ///
    /// - parameter rect: 剪切矩形
    ///
    /// - returns: 剪切后的图像
    func cropping(with rect: CGRect) -> UIImage? {
        let scale = UIScreen.main.scale
        let rect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.width * scale, height: rect.height * scale)
        guard let cgImage = cgImage?.cropping(to: rect) else { return nil }
        return UIImage(cgImage: cgImage)
    }
    
    /// 根据给定的时间戳截止视频的图片
    ///
    /// - parameter videoPath: 视频路径
    /// - parameter times:     给定的时间戳
    ///
    /// - returns: 截取的图片
    class func generateThumbImages(withVideoPath videoPath: String, atTime times: [Float64]) -> [UIImage] {
        return self.generateThumbImages(withVideoURL: URL(fileURLWithPath: videoPath), atTime: times)
    }
    
    /// 根据给定的时间戳截止视频的图片
    ///
    /// - parameter videoURL: 给定的时间戳
    /// - parameter times:    视频的 URL 链接
    ///
    /// - returns: 截取的图片
    class func generateThumbImages(withVideoURL videoURL: URL, atTime times: [Float64]) -> [UIImage] {
        
        var thumbImg: UIImage
        var thumbImgs = [UIImage]()
        let asset = AVURLAsset(url: videoURL)
        
        let generator = AVAssetImageGenerator(asset: asset)
        generator.appliesPreferredTrackTransform = true
        
        for time in times {
            
            let timestamp = CMTimeMakeWithSeconds(time, preferredTimescale: 600)
            
            do {
                let image = try generator.copyCGImage(at: timestamp, actualTime: nil)
                thumbImg = UIImage(cgImage: image)
            } catch {
                Log_y.print_("generate image error: \(error)")
                continue
            }
            thumbImgs.append(thumbImg)
        }
        return thumbImgs
    }
}

public enum WechatCompressType {
    case session
    case timeline
}

public extension UIImage {
    func toBase64String(_ compressionQuality: Double = 1) -> String? {
        guard let imageData = UIImage.jpegData(self)(compressionQuality: compressionQuality) else {
            return nil
        }
        return imageData.base64EncodedString()
    }
    
    func toData(_ compressionQuality: Double = 1) -> Data? {
        guard let imageData = UIImage.jpegData(self)(compressionQuality: compressionQuality) else {
            return nil
        }
        return imageData
    }
}

extension UIImageView {

    public func loadGif(name: String) {
        DispatchQueue.global().async {
            let image = UIImage.gif(name: name)
            DispatchQueue.main.async {
                self.image = image
            }
        }
    }

    @available(iOS 9.0, *)
    public func loadGif(asset: String) {
        DispatchQueue.global().async {
            let image = UIImage.gif(asset: asset)
            DispatchQueue.main.async {
                self.image = image
            }
        }
    }

}

extension UIImage {

    public class func gif(data: Data) -> UIImage? {
        // Create source from data
        guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
            print("SwiftGif: Source for the image does not exist")
            return nil
        }

        return UIImage.animatedImageWithSource(source)
    }

    public class func gif(url: String) -> UIImage? {
        // Validate URL
        guard let bundleURL = URL(string: url) else {
            print("SwiftGif: This image named \"\(url)\" does not exist")
            return nil
        }

        // Validate data
        guard let imageData = try? Data(contentsOf: bundleURL) else {
            print("SwiftGif: Cannot turn image named \"\(url)\" into NSData")
            return nil
        }

        return gif(data: imageData)
    }

    public class func gif(name: String) -> UIImage? {
        // Check for existance of gif
        guard let bundleURL = Bundle.main
          .url(forResource: name, withExtension: "gif") else {
            print("SwiftGif: This image named \"\(name)\" does not exist")
            return nil
        }

        // Validate data
        guard let imageData = try? Data(contentsOf: bundleURL) else {
            print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
            return nil
        }

        return gif(data: imageData)
    }

    @available(iOS 9.0, *)
    public class func gif(asset: String) -> UIImage? {
        // Create source from assets catalog
        guard let dataAsset = NSDataAsset(name: asset) else {
            print("SwiftGif: Cannot turn image named \"\(asset)\" into NSDataAsset")
            return nil
        }

        return gif(data: dataAsset.data)
    }

    internal class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double {
        var delay = 0.1

        // Get dictionaries
        let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
        let gifPropertiesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 0)
        defer {
            gifPropertiesPointer.deallocate()
        }
        if CFDictionaryGetValueIfPresent(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque(), gifPropertiesPointer) == false {
            return delay
        }

        let gifProperties:CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self)

        // Get delay time
        var delayObject: AnyObject = unsafeBitCast(
            CFDictionaryGetValue(gifProperties,
                Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()),
            to: AnyObject.self)
        if delayObject.doubleValue == 0 {
            delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties,
                Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
        }

        if let delayObject = delayObject as? Double, delayObject > 0 {
            delay = delayObject
        } else {
            delay = 0.1 // Make sure they're not too fast
        }

        return delay
    }

    internal class func gcdForPair(_ a: Int?, _ b: Int?) -> Int {
        var a = a
        var b = b
        // Check if one of them is nil
        if b == nil || a == nil {
            if b != nil {
                return b!
            } else if a != nil {
                return a!
            } else {
                return 0
            }
        }

        // Swap for modulo
        if a! < b! {
            let c = a
            a = b
            b = c
        }

        // Get greatest common divisor
        var rest: Int
        while true {
            rest = a! % b!

            if rest == 0 {
                return b! // Found it
            } else {
                a = b
                b = rest
            }
        }
    }

    internal class func gcdForArray(_ array: Array<Int>) -> Int {
        if array.isEmpty {
            return 1
        }

        var gcd = array[0]

        for val in array {
            gcd = UIImage.gcdForPair(val, gcd)
        }

        return gcd
    }

    internal class func animatedImageWithSource(_ source: CGImageSource) -> UIImage? {
        let count = CGImageSourceGetCount(source)
        var images = [CGImage]()
        var delays = [Int]()

        // Fill arrays
        for i in 0..<count {
            // Add image
            if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
                images.append(image)
            }

            // At it's delay in cs
            let delaySeconds = UIImage.delayForImageAtIndex(Int(i),
                source: source)
            delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
        }

        // Calculate full duration
        let duration: Int = {
            var sum = 0

            for val: Int in delays {
                sum += val
            }

            return sum
            }()

        // Get frames
        let gcd = gcdForArray(delays)
        var frames = [UIImage]()

        var frame: UIImage
        var frameCount: Int
        for i in 0..<count {
            frame = UIImage(cgImage: images[Int(i)])
            frameCount = Int(delays[Int(i)] / gcd)

            for _ in 0..<frameCount {
                frames.append(frame)
            }
        }

        // Heyhey
        let animation = UIImage.animatedImage(with: frames,
            duration: Double(duration) / 1000.0)

        return animation
    }

}
